#pragma once

#include "Business/Dealing.h"
#include "Business/Band.h"
#include "Business/Leg.h"

class ArbitrageContracts;
class MarketStorage;
class PositionValue;

class ArbitrageLegs
{
public:
	static ArbitrageLegs CreateBearish(MarketStorage const& marketStorage,ArbitrageContracts const& contracts);
	static ArbitrageLegs CreateBullish(MarketStorage const& marketStorage,ArbitrageContracts const& contracts);
	static ArbitrageLegs Create(MarketStorage const& marketStorage,Band const& band,ArbitrageContracts const& contracts);

	Leg const& GetFartherOpenLeg() const { return m_fartherOpenLeg; }
	Leg const& GetNearbyOpenLeg() const { return m_nearbyOpenLeg; }
	Leg const& GetFartherOffsetLeg() const { return m_fartherOffsetLeg; }
	Leg const& GetNearbyOffsetLeg() const { return m_nearbyOffsetLeg; }
	Leg const& GetMinorOpenLeg() const { return m_minorOpenLeg; }
	Leg const& GetMajorOpenLeg() const { return m_majorOpenLeg; }
	Leg const& GetMinorOffsetLeg() const { return m_minorOffsetLeg; }
	Leg const& GetMajorOffsetLeg() const { return m_majorOffsetLeg; }

	void UpdateBandByBollinger(Bollinger const& bollinger)
	{
		m_band.UpdateByBollinger(bollinger);
	}

	bool UpdateBand(Band const& band);

	bool CanOpen() const
	{
		return m_band.CanOpen(GetOpenBalance(),GetStopBalance());
	}

	bool CanOpen(Dealing const& openedDealing) const
	{
		return m_band.CanOpen(GetOpenBalance(openedDealing),GetStopBalance(openedDealing));
	}
	bool IsLostOpenMarket(Dealing const& openedDealing) const
	{
		return m_band.IsLostOpenMarket(GetOpenBalance(openedDealing),GetStopBalance(openedDealing),m_minorOpenLeg.GetMarket().GetMinPriceUnit());
	}
	bool IsOpenMarket(Dealing const& openedDealing) const
	{
		return m_band.IsOpenMarket(GetOpenBalance(openedDealing),GetStopBalance(openedDealing),m_minorOpenLeg.GetMarket().GetMinPriceUnit());
	}
	bool CanOffset() const
	{
		return m_band.CanOffset(GetOffsetBalance());
	}

	bool CanStop() const
	{
		return m_band.CanStop(GetStopBalance());
	}

	double GetOpenBalance() const
	{
		return GetFartherOpenLeg().GetPrice() - GetNearbyOpenLeg().GetPrice();
	}

	double GetOffsetBalance() const
	{
		return GetFartherOffsetLeg().GetPrice() - GetNearbyOffsetLeg().GetPrice();
	}

	double GetStopBalance() const 
	{
		return GetOffsetBalance();
	}

	double GetOpenBalance(Dealing const& openedDealing) const;

	double GetOffsetBalance(Dealing const& openedDealing) const;

	double GetStopBalance(Dealing const& openedDealing) const 
	{
		return GetOffsetBalance(openedDealing);
	}


	int GetOpenQuantity() const 
	{
		return min(m_fartherOpenLeg.GetQuantity(),m_nearbyOpenLeg.GetQuantity());
	}

	int GetOffsetQuantity() const 
	{
		return min(m_fartherOffsetLeg.GetQuantity(),m_nearbyOffsetLeg.GetQuantity());
	}

	double GetOpenFreezeAmount(int quantity) const
	{
		return GetFartherOpenLeg().GetFreezeAmount(quantity) + GetNearbyOpenLeg().GetFreezeAmount(quantity);
	}

	Band const& GetBand() const { return m_band; }

	bool Match(int contract, Direction::TYPE direction, Operation::TYPE operation) const
	{
		return GetFartherOpenLeg().Match(contract,direction,operation) ||
			GetNearbyOpenLeg().Match(contract,direction,operation) ||
			GetFartherOffsetLeg().Match(contract,direction,operation) ||
			GetNearbyOffsetLeg().Match(contract,direction,operation);
	}

	double GetProfit(double balance, int quantity) const;

	bool IsMajorEqualFarther() const
	{
		return m_majorOpenLeg.GetContract() == m_fartherOpenLeg.GetContract();
	}

	ArbitrageLegs(ArbitrageLegs const& other);

private:
	ArbitrageLegs(MarketStorage const& marketStorage,ArbitrageContracts const& contract,Direction::TYPE fartherDirection,Band const& band);

	Leg m_fartherOpenLeg;
	Leg m_nearbyOpenLeg;
	Leg m_fartherOffsetLeg;
	Leg m_nearbyOffsetLeg;
	Band m_band;

	Leg& m_minorOpenLeg;
	Leg& m_majorOpenLeg;
	Leg& m_minorOffsetLeg;
	Leg& m_majorOffsetLeg;
};

